package com.dragon.english_practice_back.controller;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dragon.english_practice_back.controller.dto.TranslateAnswerDTO;
import com.dragon.english_practice_back.entity.AIJson.TranslateQuestion;
import com.dragon.english_practice_back.service.AuthenticationUtil;
import com.dragon.english_practice_back.service.ExerciseService;
import com.dragon.english_practice_back.service.ResponseAnalysisService;
import com.dragon.english_practice_back.service.TranslateService;
import com.dragon.english_practice_back.entity.Translate;
import com.dragon.english_practice_back.enums.TranslateQuestionType;
import com.dragon.english_practice_back.reponse.Result;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.deepseek.DeepSeekChatOptions;
import org.springframework.ai.deepseek.api.ResponseFormat;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;

import java.util.List;
import java.util.Map;

@RestController
@AllArgsConstructor
@RequestMapping("translate")
@Slf4j
public class TranslateController {
    private final ChatClient deepSeekChatClient;
    private final ObjectMapper objectMapper;
    private final AuthenticationUtil authenticationUtil;
    private final ExerciseService exerciseService;
    private final TranslateService translateService;
    ResponseAnalysisService responseAnalysisService;

    @GetMapping("getOneQuestion")
    public Result<TranslateQuestion> getOneQuestion(@RequestParam String type) {
        TranslateQuestionType typeEnum = TranslateQuestionType.getByValue(type);
        if (typeEnum == null) {
            return Result.no("题目类型错误, type(ECT or CET)");
        }
        TranslateQuestion translate = exerciseService.getOneQuestion(typeEnum);
        if (translate == null) {
            return Result.no("没有题目了,正在个性化出题中,请稍后再试");
        }
        return Result.ok("", translate);
    }


    @PostMapping("calculateScore")
    public Result<Object> calculateScore(@RequestBody TranslateAnswerDTO answer) {
        // 如果问题为空,返回错误
        if (answer.getQuestion() == null) {
            return Result.no("问题不能为空，请刷新问题", Map.of("score", 0));
        }
        // 如果用户答案为空,返回错误
        if (answer.getUserAnswer() == null) {
            return Result.no("用户答案不能为空", Map.of("score", 0));
        }
        // 检查是否登录,能取到id表示已经登录,如果取不到idAuthentication会抛出异常并返回错误
        authenticationUtil.id();

        // 计算分数 and 保存到数据库
        // 询问deepseek 分数
        Message systemMessage =
                new SystemMessage(
                        """
                                你是一个英语翻译打分员,你的任务是根据用户的翻译结果给出分数。

                                你的回答格式为JSON。
                                JSON示例：
                                {
                                    "score": 80
                                }

                                用户消息会给你翻译的题目和翻译的结果。
                                用户可能会给你的是JSON形式的数据,如果是JSON形式的:question表示题目,standardAnswer表示标准答案,userAnswer表示用户的答案。
                                用户传递给你的数据可能会有标准答案，但你不需要使用它，你只关注原问题和用户回答，你根据自己的知识给出分数。
                                评分标准：
                                1. 满分100分,分成语法错误和词汇错误。
                                2. 语法错误：占50的分值,有一处语法错误扣10分,如果全错得0分。
                                3. 词汇错误：占50的分值,有一处词汇错误扣5分,如果全错得0分。

                                """
                );
        Message userMessage =
                new UserMessage(
                        JSONUtil.toJsonStr(answer));
        String contentScore = deepSeekChatClient.prompt()
                .messages(List.of(systemMessage, userMessage))
                .options(DeepSeekChatOptions.builder()
                        .temperature(1.7)
                        .responseFormat(ResponseFormat.builder().type(ResponseFormat.Type.JSON_OBJECT).build())
                        .build())
                .call().content();

        Integer score = 0;
        try{

            // 判断content是否为空
            if (StrUtil.isNotEmpty(contentScore)) {
                // 判断content是否是JSON
                if (JSONUtil.isTypeJSON(contentScore)) {
                    // 获取score
                    score = JSONUtil.parseObj(contentScore).getInt("score");
                }
            }
        }
        catch (Exception e) {
            log.error("calculateScore error: {}", e.getMessage());
            return Result.no("计算分数失败");
        }

        // 保存到数据库
        Translate translate = new Translate();
        translate.setQuestion(answer.getQuestion());
        translate.setStandardAnswer(answer.getStandardAnswer());
        translate.setUserAnswer(answer.getUserAnswer());
        translate.setAccuracy(score);
        translate.setUserId(authenticationUtil.id());

        translateService.save(translate);

        // 分析用户的回答
        responseAnalysisService.analysis(authenticationUtil.id(), answer.getQuestion(), answer.getUserAnswer());

        return Result.ok("计算分数成功", Map.of("score", score));

    }

    @SneakyThrows
    public String toJson(ChatResponse chatResponse) {
        return objectMapper.writeValueAsString(chatResponse);
    }
    //使用deepseek做翻译助手建议
    @PostMapping("assistantSuggestion")
    public Flux<ServerSentEvent<String>> assistantSuggestion(@RequestBody TranslateAnswerDTO answer) {
        // 使用deepseek做翻译助手建议
        Message systemMessage =
                new SystemMessage(
                        """
                                你是一个英语翻译评价员，你的任务是根据用户的翻译结果给出评价。
                                你的回答要自然,要像在聊天一样,不要格式化。
                                用户会给你翻译的题目和翻译的结果。
                                用户可能给你的是JSON形式的数据,如果是JSON形式的:question表示题目,standardAnswer表示标准答案,userAnswer表示用户的答案。
                                用户传递给你的数据可能会有标准答案，但你不需要使用它，你只关注原问题和用户回答，也不要在用户回答中提到标准答案的字样，你根据自己的知识给出评价。
                                评价标准：
                                1. 语法错误：如果用户的翻译结果有语法错误，你应该给出纠正建议。
                                2. 词汇错误：如果用户的翻译结果有词汇错误，你应该给出纠正建议。
                                3. 翻译准确性：如果用户的翻译结果准确，你应该给出鼓励。
                                4. 翻译流畅性：如果用户的翻译结果流畅，你应该给出鼓励。
                                5. 翻译风格：如果用户的翻译结果风格良好，你应该给出鼓励。
                                6. 翻译效率：如果用户的翻译结果效率高，你应该给出鼓励。
                                
                                """);
        Message userMessage =
                new UserMessage(
                        JSONUtil.toJsonStr(answer));
        return deepSeekChatClient.prompt().messages(List.of(systemMessage, userMessage))
                .stream()                // 构造SSE（ServerSendEvent）格式返回结果
                .chatResponse()
                .map(chatResponse -> ServerSentEvent.builder(toJson(chatResponse))
                        .event("message")
                        .build())
                .onErrorResume(e -> {
                    log.error("AI访问出错: {}", e.getMessage());
                    return Flux.just(ServerSentEvent.builder("访问太频繁了")
                            .event("error")
                            .build());
                });

    }

    // 分页获取用户的翻译记录
    @GetMapping("getTranslateRecord")
    public Result<Page<Translate>> getTranslateRecord(@RequestParam Integer pageNum, @RequestParam Integer pageSize) {
        // 分页获取用户的翻译记录,使用mybatis-plus的分页插件
        Page<Translate> page = new Page<>(pageNum, pageSize);
        Page<Translate> translatePage = translateService.page(page, new QueryWrapper<Translate>()
                .select("id", "question", "standard_answer", "user_answer", "accuracy")
                .eq("user_id", authenticationUtil.id())
        );
        return Result.ok("", translatePage);
    }
}
